/**
 * Created with JavaScript.
 * User: rgxmg
 * Email: rgxmg@foxmail.com
 * Date: 2020/8/19
 * Time: 20:16
 * Drawer组件，其实就是在elementUI的基础上
 * 增加了底部俩个按钮，并且处理了body的高度滚动
 * 以及增加了title和footer的分割线
 *
 * scopedSlots: {
 *   footerOverwrite: 完全覆盖footer区域(保留分割线)
 *   btnExtra: 按钮扩展，处于ok以及cancel之间
 * }
 */
import { Button, Drawer } from 'element-ui';
import styled from './index.module.less';
import './override.css';
import { isPromise } from '@utils/dataHandler';

export default {
  name: 'SDrawer',
  components: {
    Drawer,
    Button,
  },
  props: {
    // 底部按钮
    // 传递空数组代表不要底部按钮
    // ok 按钮 默认text为确认 监听事件为@ok
    // cancel 按钮 默认text为取消 监听事件为@cancel
    btns: {
      type: Array,
      default: () => ['ok', 'cancel'],
      validator(val) {
        const list = ['ok', 'cancel'];
        if (!Array.isArray(val)) return false;
        for (const i of val) {
          if (!~list.indexOf(i)) return false;
        }
        return true;
      },
    },
    // ok按钮的text文字描述
    okText: String,
    // cancel按钮的text文字描述
    cancelText: String,
    appendToBody: {
      type: Boolean,
      default: false,
    },
    beforeClose: {
      type: Function,
    },
    customClass: {
      type: String,
      default: '',
    },
    closeOnPressEscape: {
      type: Boolean,
      default: true,
    },
    destroyOnClose: {
      type: Boolean,
      default: false,
    },
    modal: {
      type: Boolean,
      default: true,
    },
    direction: {
      type: String,
      default: 'rtl',
      validator(val) {
        return ['ltr', 'rtl', 'ttb', 'btt'].indexOf(val) !== -1;
      },
    },
    modalAppendToBody: {
      type: Boolean,
      default: true,
    },
    showClose: {
      type: Boolean,
      default: true,
    },
    size: {
      type: String,
      default: '30%',
    },
    title: {
      type: String,
      default: '',
    },
    visible: {
      type: Boolean,
    },
    wrapperClosable: {
      type: Boolean,
      default: true,
    },
    withHeader: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      // 原始drawer的ref
      $ref: null,
      // ok按钮的loading效果
      loadingOfOk: false,
    };
  },
  methods: {
    onClose() {
      // visible.async
      this.$emit('update:visible', false);
      this.$emit('close');
    },
    onOk(e) {
      e.stopPropagation();
      const result = this.$listeners?.ok?.();
      if (isPromise(result)) {
        this.loadingOfOk = true;
        result.finally(this.$NotShake(() => (this.loadingOfOk = false)));
      }
    },
    onCancel() {
      this.$emit('cancel');
      this.onClose();
    },
    toClose() {
      if (this.$ref) {
        this.$ref.closeDrawer();
      }
    },
    renderOkBtn() {
      return (
        <Button loading={this.loadingOfOk} onClick={this.onOk} size="medium" type="primary">
          {this.okText || '确认'}
        </Button>
      );
    },
    renderCancelBtn() {
      return (
        <Button type="danger" onClick={this.onCancel} size="medium">
          {this.cancelText || '取消'}
        </Button>
      );
    },
    renderBtns() {
      const { btns, $scopedSlots } = this;
      return btns.length ? (
        <div class={styled.drawerActionWrap}>
          {$scopedSlots.footerOverwrite?.()
            ? null
            : [
                ~btns.indexOf('ok') && this.renderOkBtn(),
                $scopedSlots.btnExtra?.() || null,
                ~btns.indexOf('cancel') && this.renderCancelBtn(),
              ]}
        </div>
      ) : null;
    },
    renderTitle() {
      return this.$slots.title ? null : (
        <div slot="title" class={styled.headerWrap}>
          <div class={styled.title}>{this.title}</div>
          <button
            onClick={this.toClose}
            type="button"
            class={styled.closeAction + ' el-drawer__close-btn'}
          >
            <i class="el-dialog__close el-icon el-icon-close" />
          </button>
        </div>
      );
    },
  },
  watch: {
    /**
     * 此处加上visible是为了解决el-drawer的bug
     * 当从el-drawer处触发visible值得改变时，如点击el-drawer的遮罩层等，就会触发destroy-on-close属性的功能
     * 反之从外部并不会改变，所以需要hack处理
     * @param v
     */
    visible(v) {
      if (v === false && !this.$ref?.closed) {
        this.$ref?.closeDrawer();
      }
    },
  },
  render() {
    const props = {
      props: {
        ...this.$props,
        // 取消自带的关闭按钮
        showClose: false,
      },
      attrs: {
        ...this.$attrs,
      },
      on: {
        ...this.$listeners,
        close: this.onClose,
      },
      directives: [{ name: 'ref', value: ref => (this.$ref = ref) }],
    };
    const { default: children, ...restChildren } = this.$slots;
    return (
      <Drawer {...props}>
        {this.renderTitle()}
        {this.renderBtns()}
        <div class={`${styled.bodyWrap} ${this.btns.length ? '' : styled.noBtns}`}>{children}</div>
        {Object.keys(restChildren).reduce((m, c) => [...m, <i slot={c}>{this.$slots[c]}</i>], [])}
      </Drawer>
    );
  },
};
